package com.zh.ssmshirofreemarker.shiro;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zh.ssmshirofreemarker.entity.User;
import com.zh.ssmshirofreemarker.service.IRolePermissionService;
import com.zh.ssmshirofreemarker.service.IUserRoleService;
import com.zh.ssmshirofreemarker.service.IUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

public class MyShiroRealm extends AuthorizingRealm {

    public static String REALM_NAME = "com.zh.ssmshirofreemarker.shiro.MyShiroRealm";

    @Autowired
    IUserService userService;

    @Autowired
    IUserRoleService userRoleService;

    @Autowired
    IRolePermissionService rolePermissionService;

    /**
     *  进行认证操作
     *  1.从token 中获取登陆的用户名
     *  2.通过用户名从数据库中取出密码
     *  3.创建 SimpleAuthenticationInfo 实例，并返回
     * @param token
     * @return
     * @throws AuthenticationException
     */
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1.把AuthenticationToken 强转
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        //2.从usernamePasswordToken 中获取username
        String username = usernamePasswordToken.getUsername();

        //3.从数据库中查询username对应的记录
        User user = new User(username);
        try{
            user = userService.selectOne(new EntityWrapper<User>().eq("username",username));
        } catch (Exception e){
            e.printStackTrace();
        }

        ByteSource salt = ByteSource.Util.bytes(username);    //盐值

        //4.对前台传过来的密码进行加密
//        String algorithmName = "MD5";    //使用的加密算法
//        Object source = usernamePasswordToken.getPassword();        //密码的明文
//        int hashIterations = 1;          //加密的次数
//        ByteSource salt = ByteSource.Util.bytes(username);              //盐值
//        Object result = new SimpleHash(algorithmName, source, salt, hashIterations); // 加密算法，密码的明文，加密的盐值，加密的次数
        /**
        *  第一个参数是从数据库中查出的用户名
         *  第二个参数是从数据库中查出的密码
         *  第三个参数是盐值
         *  第四个参数是获取realm 的真实名称
        * */
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),salt,getName());
        return info;
    }

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        //1.从PrincipalCollection 获取登录用户的信息
        Object principal = principals.getPrimaryPrincipal();

        //2.利用登陆的信息来查询当前用户的角色和权限（需要查询数据库）
        User user = new User(principal.toString());
        Set<String> roles = userRoleService.getRolesByUsername(user);
        Set<String> permissions = rolePermissionService.getPermissionByUserName(user);

        //3.设置角色和权限
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roles);   //设置角色
        info.setStringPermissions(permissions);  //设置权限

        return info;
    }

    public  void clearCachedAuthenticationInfo(){
        super.clearCachedAuthenticationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    public void clearCachedAuthorizationInfo(){
        super.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    //静态清除 认证 缓存的方法
    public static void clearCachedAuthentication(){
        MyShiroRealm realm = getMyShiroRealm();
        realm.clearCachedAuthenticationInfo();
    }
    //静态清除 授权 缓存的方法
    public static void clearCachedAuthorization(){
        MyShiroRealm realm = getMyShiroRealm();
        if(realm != null){
            realm.clearCachedAuthorizationInfo();
        }
    }


    /**
     *  从 RealmSecurityManager 中获取当前 ShiroRealm的实例
     * @return
     */
    private static MyShiroRealm getMyShiroRealm() {
        RealmSecurityManager rsm = (RealmSecurityManager) SecurityUtils.getSecurityManager();
        Iterator iterator =  rsm.getRealms().iterator();
        MyShiroRealm realm = null;
        while(iterator.hasNext()){
             if(iterator.next() instanceof MyShiroRealm){
                 realm = (MyShiroRealm) rsm.getRealms().iterator().next();
                 break;
             }
        }
        return realm;
    }

}
